var GFWindowBehavior = Base.extend({
	constructor: function() {},
	PreCreateWindow: function(win) {},
	PostCreateWindow: function(win) {},
	DestroyWindow: function(win) {},
	SetFocus: function(win) {},
	BringToTop: function(win) {},
	SetWindowPosition: function(win,x,y) {},
	ShowWindow: function(win) {},
	SetContent: function(win) {}
});

var GFWindowsMovableHandler; // to prevent some javascript error 

var firefox_mousemove = function(e) { return GFWindowsMovableHandler.onmousemove(e); };
var firefox_mousedown = function(e) { return GFWindowsMovableHandler.onmousedown(e); };
var firefox_mouseup = function(e) { return GFWindowsMovableHandler.onmouseup(e); };
var firefox_scroll = function(e) { return GFWindowsMovableHandler.onscroll(e); }; // should not be called.

GFWindowsMovableHandler = Base.extend({
	registered_id: {},
	moving_win: null,
	mouse_offsetx: null,
	mouse_offsety: null,
	top_z: 1,
	constructor: null,
	old_onscroll: null,
	old_onresize: null,
	last_width: null,
	last_height: null,
	init: function()
	{	
		var x = this;

		if(GownFullBrowserDetect.use_css_position_fixed) {
			Debug.trace(0,"GFWindowsMovableHandler: Using position: fixed, attached onresize event.");
			this.old_onresize = window.onresize;
			window.onresize = function() { return x.onresize(window.event); }
		}
		else if(GownFullBrowserDetect.use_css_position_absolute) {
			this.old_onscroll = window.onscroll;
			window.onscroll = function() { return x.onscroll(window.event); }
			this.old_onresize = window.onresize;
			window.onresize = function() { return x.onresize(window.event); }
			Debug.trace(0,"GFWindowsMovableHandler: Using position: absolute, attached onscroll/onresize event.");
		}
		else {
			Debug.trace(0,"GFWindowsMovableHandler: Movable Window is not supported in this browser.");
		}
		this.last_width = this.GetClientWidth();
		this.last_height = this.GetClientHeight();
	},
	skipnodeName: {
		'textarea': true,
		'input': true,
		'select': true,
		'a': true,
		'button': true
	},
	GetScrollX: function()
	{
		var t = 0;

		if(t == 0 && document.documentElement) t = document.documentElement.scrollLeft;
		if(t == 0 && document.body) t = document.body.scrollLeft;

		return t;
	},
	GetScrollY: function()
	{
		var t = 0;

		if(t == 0 && document.documentElement) t = document.documentElement.scrollTop;
		if(t == 0 && document.body) t = document.body.scrollTop;

		return t;
	},
	GetClientWidth: function()
	{
		var t = 0;

		if(t == 0 && document.documentElement) t = document.documentElement.clientWidth;
		if(t == 0 && document.body) t = document.body.clientWidth;

		return t;
	},
	GetClientHeight: function()
	{
		var t = 0;

		if(t == 0 && document.documentElement) t = document.documentElement.clientHeight;
		if(t == 0 && document.body) t = document.body.clientHeight;

		return t;
	},
	SetXY: function(win,x,y)
	{
		if(win.id) {
			this.registered_id[win.id] = [x,y];
			Debug.trace(4,"GFWindowsMovableHandler: Set window id=%s to position (%s).",win.id,this.registered_id[win.id]);
		}
		else {
			Debug.trace(0,"GFWindowsMovableHandler: WARNING: win has no id.");
		}
		
		if(GownFullBrowserDetect.use_css_position_fixed) {
			win.style.left = lib.sprintf('%dpx',x);
			win.style.top = lib.sprintf('%dpx',y);
		}
		else if(GownFullBrowserDetect.use_css_position_absolute) {
			win.style.left = lib.sprintf('%dpx',x + this.GetScrollX());
			win.style.top = lib.sprintf('%dpx',y + this.GetScrollY());
		}
	},
	RegisterWindow: function(div_obj,id,init_x,init_y)
	{	
		var x = this;

		if(GownFullBrowserDetect.use_mouse_addEventListener) {
			div_obj.addEventListener("mousemove", firefox_mousemove,true);
			div_obj.addEventListener("mousedown", firefox_mousedown,true);
			div_obj.addEventListener("mouseup", firefox_mouseup,true);
		}
		else if(GownFullBrowserDetect.use_attachEvent) {
			div_obj.attachEvent("onmousemove", function(e) { return x.onmousemove(e); });
			div_obj.attachEvent("onmousedown", function(e) { return x.onmousedown(e); });
			div_obj.attachEvent("onmouseup", function(e) { return x.onmouseup(e); });
		}	
		else { // use the most generic one (probably fails)
			div_obj.onmousemove = function() { return x.onmousemove(window.event); }
			div_obj.onmousedown = function() { return x.onmousedown(window.event); }
			div_obj.onmouseup = function() { return x.onmouseup(window.event); }
		}
		div_obj.style.zIndex = this.top_z++;
		this.registered_id[id] = [init_x,init_y];
		Debug.trace(0,'GFWindowsMovableHandler: Register a window (id=%s)',id);
	},
	UnregisterWindow: function(id)
	{
		this.registered_id[id] = false;
		delete this.registered_id[id];
		// FIXME
		Debug.trace(0,'GFWindowsMovableHandler: Unregister a window (id=%s)',id);
	},
	GetParentDiv: function(obj)
	{
		while(obj) {
			if(obj.id && this.registered_id[obj.id] && obj.tagName.toLowerCase() == 'div') return obj;
			if(obj.parentElement) obj = obj.parentElement;
			else return null;
		}
		return null;
	},
	onscroll: function(e)
	{
		for(var key in this.registered_id) {
			Debug.trace(3,'GFWindowsMovableHandler (onscroll): handling for id=%s',key);
			var d = document.getElementById(key);
			var pos = this.registered_id[key];
			if(!d) {
				Debug.trace(0,'GFWindowsMovableHandler (onscroll): Something get wrong, getElementById(%s) fails',key);
				continue;
			}
			this.SetXY(d,pos[0],pos[1]);
		}
		if(this.old_onscroll) this.old_onscroll();
	},
	onresize: function(e)
	{
		for(var key in this.registered_id) {
			var d = document.getElementById(key);
			var pos = this.registered_id[key];

			Debug.trace(3,'GFWindowsMovableHandler (onresize): handling for id=%s, lastwh=(%d,%d), oldpos=(%s)',key,this.GetClientWidth(),this.GetClientHeight(),pos);

			if(!d) {
				Debug.trace(0,'GFWindowsMovableHandler (onresize): Something get wrong, getElementById(%s) fails',key);
				continue;
			}
			pos[0] = (pos[0] / this.last_width) * this.GetClientWidth();
			pos[0] = Math.round(pos[0]);
			pos[1] = (pos[1] / this.last_height) * this.GetClientHeight();
			pos[1] = Math.round(pos[1]);
			this.SetXY(d,pos[0],pos[1]);
		}
		this.last_width = this.GetClientWidth();
		this.last_height = this.GetClientHeight();
		if(this.old_onresize) this.old_onresize();
	},
	onmousedown: function(e)
	{
		var curr = e.srcElement || e.target;
		var win = e.currentTarget || this.GetParentDiv(curr);

		if(win && win.id) {
			if(!this.registered_id[win.id]) return;
		}
		if(curr && curr.nodeName) {
			var nodename = curr.nodeName.toLowerCase();

			if(this.skipnodeName[nodename] == true) return;
			if(nodename == 'div' && !this.registered_id[curr.id]) return;
		}

		if(win) {
			win.style.zIndex = this.top_z++;
			
			this.AttachDocumentHandler(true);
			this.moving_win = win;
			if(GownFullBrowserDetect.use_css_position_fixed) {
				this.mouse_offsetx = e.clientX - win.offsetLeft;
				this.mouse_offsety = e.clientY - win.offsetTop;
			}
			else if(GownFullBrowserDetect.use_css_position_absolute) {
				this.mouse_offsetx = e.clientX + this.GetScrollX() - win.offsetLeft;
				this.mouse_offsety = e.clientY + this.GetScrollY() - win.offsetTop;
			}
			if(e.preventDefault) e.preventDefault();
			else {
				document.onselectstart = function () { return false; };
				e.cancelBubble = true;
				return false;
			}
		}
	},
	onmousemove: function(e)
	{
		if(this.moving_win) {
			if (!e.preventDefault) {
				if(e.button == 0) {
					this.StopDrag(e);
					return;
				}
			}
			GFWindowsMovableHandler.SetXY(this.moving_win,e.clientX - this.mouse_offsetx,e.clientY - this.mouse_offsety);
			if(e.preventDefault) e.preventDefault();
			else {
				e.cancelBubble = true;
				return false;
			}
		}
	},
	onmouseup: function(e)
	{
		if(this.moving_win) this.StopDrag(e);
	},
	StopDrag: function(e)
	{
		var finalX = e.clientX - this.mouse_offsetx;
		var finalY = e.clientY - this.mouse_offsety;
	
		if(finalX < 0) finalX = 0;
		if(finalY < 0) finalY = 0;
	
		GFWindowsMovableHandler.SetXY(this.moving_win,finalX,finalY);
	
		this.AttachDocumentHandler(false);
		this.moving_win = null;
		if(e.preventDefault) e.preventDefault();
		else {
			document.onselectstart = null;
			e.cancelBubble = true;
			return false;
		}
	},
	AttachDocumentHandler: function(attach)
	{
		var x = this;
		
		if(attach) {
			if(GownFullBrowserDetect.use_mouse_addEventListener) {
				document.addEventListener("mousemove", firefox_mousemove,true);
				document.addEventListener("mousedown", firefox_mousedown,true);
				document.addEventListener("mouseup", firefox_mouseup,true);
			}
			else {
				document.onmousedown = function() { return x.onmousedown(window.event); } ;
				document.onmousemove = function() { return x.onmousemove(window.event); } ;
				document.onmouseup = function() { return x.onmouseup(window.event); } ;
			}
		}
		else {
			if(GownFullBrowserDetect.use_mouse_addEventListener) {
				document.removeEventListener("mousemove", firefox_mousemove,true);
				document.removeEventListener("mousedown", firefox_mousedown,true);
				document.removeEventListener("mouseup", firefox_mouseup,true);
			}
			else {
				document.onmousedown = null;
				document.onmousemove = null;
				document.onmouseup = null;
			}
		}
	}
});

var GFWindowMovableBehavior = GFWindowBehavior.extend({
	init_x: 0,
	init_y: 0,
	width: null,
	height: null,
	div_obj: null,
	class_name: null,
	obj_id: null,
	constructor: function(id,init_x,init_y,width,height,class_name)
	{
		this.obj_id = id;
		if(init_x) this.init_x = init_x;
		if(init_y) this.init_y = init_y;
		if(width) this.width = width;
		if(height) this.height = height;
		if(class_name) this.class_name = class_name;
	},
	PreCreateWindow: function(win)
	{
		this.div_obj = document.createElement('div');
		this.div_obj.id = this.obj_id;
		this.div_obj.className = this.class_name;

		if(this.width != null) this.div_obj.style.width = lib.sprintf('%dpx',this.width);
		if(this.height != null) this.div_obj.style.height = lib.sprintf('%dpx',this.height);

		if(GownFullBrowserDetect.use_css_position_fixed) {
			this.div_obj.style.position = 'fixed';
		}
		else if(GownFullBrowserDetect.use_css_position_absolute) {
			this.div_obj.style.position = 'absolute';
		}
		GFWindowsMovableHandler.SetXY(this.div_obj,this.init_x,this.init_y);
		GFWindowsMovableHandler.RegisterWindow(this.div_obj,this.obj_id,this.init_x,this.init_y);
	},
	PostCreateWindow: function(win)
	{
		document.body.appendChild(this.div_obj);
	},
	DestroyWindow: function(win)
	{
		GFWindowsMovableHandler.UnregisterWindow(this.obj_id);
		document.body.removeChild(this.div_obj);
		this.div_obj = null;
	},
	SetFocus: function(win)
	{
		if(this.div_obj.focus) this.div_obj.focus();
		return true;
	},
	BringToTop: function(win)
	{
		this.div_obj.style.zIndex = GFWindowsMovableHandler.top_z++;
		return true;
	},
	SetWindowPosition: function(win,x,y)
	{
		GFWindowsMovableHandler.SetXY(this.div_obj,x,y);
		return true;
	},
	ShowWindow: function(win,show)
	{
		if(show) this.div_obj.style.display = 'block';
		else this.div_obj.style.display = 'none';
		return true;
	},
	SetContent: function(win,content)
	{
		this.div_obj.innerHTML = content;
	}
});

var GFWindowFixedBehavior = GFWindowBehavior.extend({
	div_id: null,
	div_obj: null,
	class_name: null,
	constructor: function(div_id,class_name)
	{
		this.div_id = div_id;
		this.div_obj = document.getElementById(div_id);
		this.class_name = class_name;
	},
	PreCreateWindow: function(win)
	{
		this.div_obj.className = this.class_name;
	},
	PostCreateWindow: function(win)
	{
	},
	DestroyWindow: function(win)
	{
		this.div_obj.innerHTML = '';
		this.div_obj = null;
	},
	SetFocus: function(win)
	{
		if(this.div_obj.focus) this.div_obj.focus();
		return true;
	},
	BringToTop: function(win)
	{
		return true;
	},
	SetWindowPosition: function(win,x,y)
	{
		return true;
	},
	ShowWindow: function(win,show)
	{
		if(show) this.div_obj.style.display = 'block';
		else this.div_obj.style.display = 'none';
		return true;
	},
	SetContent: function(win,content)
	{
		this.div_obj.innerHTML = content;
	}
});

var GFWindow = Base.extend({
	behavior: null,
	shown: false,
	constructor: function(behavior,hidden,content)
	{
		this.behavior = behavior;
		this.behavior.PreCreateWindow(this);
		this.shown = !hidden;
		this.behavior.ShowWindow(this,!hidden);
		this.behavior.SetContent(this,content);
		this.behavior.PostCreateWindow(this);
	},
	ShowWindow: function(show) { this.shown = show; return this.behavior.ShowWindow(this,show); },
	DestroyWindow: function() { return this.behavior.DestroyWindow(this); },
	SetFocus: function() { return this.behavior.SetFocus(this); },
	BringToTop: function() { return this.behavior.BringToTop(this); },
	SetWindowPosition: function(x,y) { return this.behavior.SetWindowPosition(this,x,y); }
});
